/**
 * @package Infinity-Seed
 * @subpackage view
 *
 * @copyright Copyright (C) 2012-2013 Exia.CESI
 * @author Paul MAGNIN, Arthur MERCIER, Jordan RICHET, Cyril SCHUMACHER
 */
package view;

import infinity.seed.CellState;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 * Fenêtre de gestion de la grille.
 *
 * @author Cyril SCHUMACHER <cyril.schumacher at viacesi.fr>
 * @author Arthur MERCIER <arthur.mercier at viacesi.fr>
 * @author Jordan RICHET <jordan.richet at viacesi.fr>
 */
public class GridWindow {
    // <editor-fold defaultstate="collapsed" desc="Attributs.">
    /**
     * Fenêtre.
     */
    protected JFrame frame;
    /**
     * Position de la fenêtre de simulation.
     */
    private Point point = new Point();
    /**
     * Grille d'interaction.
     */
    protected GridCell gridCell;
    /**
     * Grille de cellule.
     */
    protected int[][] grid;
    /**
     * Configuration.
     */
    private infinity.seed.Configuration _configuration;
    /**
     * Fenêtre ActionWindow.
     */
    private ActionWindow _actionWindow;
    /**
     * Fenêtre SimulatorWindow.
     */
    private SimulatorWindow _simulatorWindow;
    /**
     * Fenêtre contenant les statistiques.
     */
    private StatsWindow _statsWindow;
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Méthodes.">
    // <editor-fold defaultstate="collapsed" desc="Constructeur.">
    /**
     * Constructeur.
     *
     * @param grid Grille de cellule.
     */
    public GridWindow(int[][] grid, SimulatorWindow simulatorWindow) {
        // Récupère une instance de la classe Configuration.
        this._configuration = infinity.seed.Configuration.getInstance();
        // Sauvegarde la grille.
        this.grid = grid;
        
        // Sauvegarde l'instance de la fenêtres.
        this._simulatorWindow = simulatorWindow;
        
        // Création de la fenêtre.
        this.frame = new JFrame("Grille (" + grid.length + "x" + grid[0].length + ")");

        // Empêche le client de fermer et de redimensionner la fenêtre.
        this.frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        this.frame.setResizable(false);
        this.frame.setBackground(Color.decode(_configuration.get("jwindow.background")));
        this.frame.setUndecorated(true);

        // Initialise les composants et la grille.
        this._InitializeComponent();
        this._InitializeGrid();

        // Redimensionne selon les composants et affiche la fenêtre selon une position.
        this.frame.pack();
        this.frame.setLocation(660, 20);
        this.frame.setVisible(true);
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Initialise les composants.">
    /**
     * Initialise les composants.
     */
    private void _InitializeComponent() {
        // Lie les événements à la fenêtre.
        GridWindowEvent windowEvent = new GridWindowEvent();
        this.frame.addMouseListener(windowEvent);
        this.frame.addMouseMotionListener(windowEvent);

        // Ajoute une disposition au contenu principale.
        BorderLayout contentPaneLayout = new BorderLayout();
        this.frame.getContentPane().setLayout(contentPaneLayout);
        this.frame.getRootPane().setBorder(BorderFactory.createLineBorder(Color.black));

        // Barre de titre.
        JPanel titlePanel = new JPanel();
        this.frame.getContentPane().add(titlePanel, BorderLayout.PAGE_START);
        titlePanel.setBackground(Color.decode(_configuration.get("jwindow.background")));
        titlePanel.setLayout(new FlowLayout(FlowLayout.RIGHT));

        JPanel spacePanel = new JPanel();
        spacePanel.setPreferredSize(new Dimension(0, 5));
        titlePanel.add(spacePanel);
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Initialise la grille.">
    /**
     * Initialise la grille.
     */
    private void _InitializeGrid() {
        // Créer une grille.
        this.gridCell = new GridCell();

        // Lie les évènements  la grille.
        GridPanelEvent gridEvent = new GridPanelEvent();
        this.gridCell.addMouseListener(gridEvent);
        this.gridCell.addMouseMotionListener(gridEvent);
        this.gridCell.setGrid(this.grid);

        // Détermine la taille des cases de la grille.
        Dimension caseSize;
        if (this.grid.length < this.grid[0].length) {
            if ((this.grid[0].length <= 10)) {
                caseSize = new Dimension(40, 40);
            } else if ((this.grid[0].length < 20)) {
                caseSize = new Dimension(40, 40);
            } else if ((this.grid[0].length < 30)) {
                caseSize = new Dimension(33, 33);
            } else if ((this.grid[0].length < 40)) {
                caseSize = new Dimension(25, 25);
            } else if ((this.grid[0].length < 50)) {
                caseSize = new Dimension(20, 20);
            } else if ((this.grid[0].length < 60)) {
                caseSize = new Dimension(16, 16);
            } else if ((this.grid[0].length < 70)) {
                caseSize = new Dimension(14, 14);
            } else if ((this.grid[0].length < 80)) {
                caseSize = new Dimension(12, 12);
            } else if ((this.grid[0].length < 90)) {
                caseSize = new Dimension(11, 11);
            } else if ((this.grid[0].length <= 100)) {
                caseSize = new Dimension(9, 9);
            } else {
                caseSize = new Dimension(45, 45);
            }
        } else if (this.grid.length > this.grid[0].length) {

            if ((this.grid.length <= 10)) {
                caseSize = new Dimension(40, 40);
            } else if ((this.grid.length < 20)) {
                caseSize = new Dimension(40, 40);
            } else if ((this.grid.length < 30)) {
                caseSize = new Dimension(33, 33);
            } else if ((this.grid.length < 40)) {
                caseSize = new Dimension(25, 25);
            } else if ((this.grid.length < 50)) {
                caseSize = new Dimension(20, 20);
            } else if ((this.grid.length < 60)) {
                caseSize = new Dimension(16, 16);
            } else if ((this.grid.length < 70)) {
                caseSize = new Dimension(14, 14);
            } else if ((this.grid.length < 80)) {
                caseSize = new Dimension(12, 12);
            } else if ((this.grid.length < 90)) {
                caseSize = new Dimension(11, 11);
            } else if ((this.grid.length <= 100)) {
                caseSize = new Dimension(9, 9);
            } else {
                caseSize = new Dimension(45, 45);
            }
        } else {
            if (((this.grid.length >= 0) && (this.grid.length < 10)) || ((this.grid[0].length >= 0) && (this.grid[0].length < 10))) {
                caseSize = new Dimension(40, 40);
            } else if (((this.grid.length >= 0) && (this.grid.length < 20)) || ((this.grid[0].length >= 0) && (this.grid[0].length < 20))) {
                caseSize = new Dimension(40, 40);
            } else if (((this.grid.length >= 0) && (this.grid.length < 30)) || ((this.grid[0].length >= 0) && (this.grid[0].length < 30))) {
                caseSize = new Dimension(33, 33);
            } else if (((this.grid.length >= 0) && (this.grid.length < 40)) || ((this.grid[0].length >= 0) && (this.grid[0].length < 40))) {
                caseSize = new Dimension(25, 25);
            } else if (((this.grid.length >= 0) && (this.grid.length < 50)) || ((this.grid[0].length >= 0) && (this.grid[0].length < 50))) {
                caseSize = new Dimension(20, 20);
            } else if (((this.grid.length >= 0) && (this.grid.length < 60)) || ((this.grid[0].length >= 0) && (this.grid[0].length < 60))) {
                caseSize = new Dimension(16, 16);
            } else if (((this.grid.length >= 0) && (this.grid.length < 70)) || ((this.grid[0].length >= 0) && (this.grid[0].length < 70))) {
                caseSize = new Dimension(14, 14);
            } else if (((this.grid.length >= 0) && (this.grid.length < 80)) || ((this.grid[0].length >= 0) && (this.grid[0].length < 80))) {
                caseSize = new Dimension(12, 12);
            } else if (((this.grid.length >= 0) && (this.grid.length < 90)) || ((this.grid[0].length >= 0) && (this.grid[0].length < 90))) {
                caseSize = new Dimension(11, 11);
            } else if (((this.grid.length >= 0) && (this.grid.length < 100)) || ((this.grid[0].length >= 0) && (this.grid[0].length < 100))) {
                caseSize = new Dimension(10, 10);
            } else {
                caseSize = new Dimension(9, 9);
            }
        }

        this.gridCell.setCaseSize(caseSize);
        this.frame.getContentPane().add(gridCell, BorderLayout.CENTER);
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Définit la fenêtre ActionWindow.">
    /**
     * Définit la fenêtre ActionWindow.
     * @param actionWindow Instance de la classe ActionWindow.
     */
    public void setActionWindow(ActionWindow actionWindow) {
        this._actionWindow = actionWindow;
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Définit la fenêtre StatsWindow.">
    /**
     * Définit la fenêtre StatsWindow.
     * @param statsWindow Instance de la classe StatsWindow.
     */
    public void setStatsWindow(StatsWindow statsWindow) {
        this._statsWindow = statsWindow;
    }
    // </editor-fold>
    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc="Evénements">
    // <editor-fold defaultstate="collapsed" desc="Evénement de la fenêtre.">
    /**
     * Evènements de la fenêtre.
     */
    private class GridWindowEvent extends MouseAdapter {

        /**
         * Recupere la position du curseur.
         * @param e Parametres.
         */
        @Override
        public void mousePressed(MouseEvent e) {
            point.x = e.getX();
            point.y = e.getY();
        }

        /**
         * Selon la position du curseur, on déplace la fenêtre.
         * @param e Parametres.
         */
        @Override
        public void mouseDragged(MouseEvent e) {
            JFrame frame = (JFrame) e.getSource();
            Point position = frame.getLocation();
            frame.setLocation(position.x + e.getX() - point.x, position.y + e.getY() - point.y);
        }
    }
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Evénement pour la grille.">
    /**
     * Evènement pour la grille.
     */
    private class GridPanelEvent extends MouseAdapter {

        /**
         * Lorsque le client clique tout en déplacant son curseur sur la grille.
         * @param e Paramètres.
         * @see GridMouseEvents::mouseClicked(); {@inheritDoc}
         */
        @Override
        public void mouseDragged(MouseEvent e) {
            this.mouseClicked(e);
        }

        /**
         * Lorsque le client clique sur l'une des cases de la grille pour ajouter un élément.
         * @param e Paramètres. {@inheritDoc}
         */
        @Override
        public void mouseClicked(MouseEvent e) {
            // Verifie si la simulation n'est pas executé.
            if ((_actionWindow.simulationThread != null) && (_actionWindow.simulationThread.isAlive())) {
                return;
            }

            int x = e.getY() / gridCell.getCaseSize().width;
            int y = e.getX() / gridCell.getCaseSize().height;

            if ((x < grid.length) && (y < grid[0].length)) {
                Integer typeCell = CellState.getValue(_simulatorWindow.radioGroup.getSelection().getActionCommand());

                if (typeCell.equals(CellState.INFECTED)) {
                    switch (grid[x][y]) {
                        case CellState.SEED:
                            grid[x][y] = CellState.SEED_INFECTED;
                            break;
                        case CellState.BUSH:
                            grid[x][y] = CellState.BUSH_INFECTED;
                            break;
                        case CellState.BUSH_1:
                            grid[x][y] = CellState.BUSH_INFECTED_1;
                        case CellState.TREE:
                            grid[x][y] = CellState.TREE_INFECTED;
                            break;
                    }
                } else if (typeCell.equals(CellState.INFIRED)) {
                    switch (grid[x][y]) {
                        case CellState.SEED:
                            grid[x][y] = CellState.SEED_INFIRED;
                            break;
                        case CellState.BUSH:
                            grid[x][y] = CellState.BUSH_INFIRED;
                            break;
                        case CellState.BUSH_1:
                            grid[x][y] = CellState.BUSH_INFIRED_1;
                            break;
                        case CellState.TREE:
                            grid[x][y] = CellState.TREE_INFIRED;
                            break;
                    }
                } else {
                    if ((x <= grid.length - 1) || (y <= grid[0].length - 1)) {
                        if ((x >= 0) && (y >= 0)) {
                            grid[x][y] = typeCell;
                        }
                    }
                }
                gridCell.setGrid(grid);
                frame.repaint();
                _statsWindow.updateStats();
            }
        }
    }
    // </editor-fold>
    // </editor-fold>
}
